import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from typing import List, Dict, Tuple, Optional
from matplotlib.patches import Patch  # 导入Patch类

class KanoModel:
    """Kano模型分析工具，用于处理调查数据、计算满意度系数并可视化结果"""
    
    # Kano类别映射
    KANO_CATEGORIES = {
        (1, 5): "魅力属性",
        (2, 5): "魅力属性",
        (3, 5): "期望属性",
        (4, 5): "期望属性",
        (5, 5): "期望属性",
        (1, 4): "魅力属性",
        (2, 4): "魅力属性",
        (3, 4): "期望属性",
        (4, 4): "期望属性",
        (5, 4): "期望属性",
        (1, 3): "魅力属性",
        (2, 3): "一元属性",
        (3, 3): "一元属性",
        (4, 3): "一元属性",
        (5, 3): "必备属性",
        (1, 2): "无差异属性",
        (2, 2): "无差异属性",
        (3, 2): "无差异属性",
        (4, 2): "反向属性",
        (5, 2): "反向属性",
        (1, 1): "无差异属性",
        (2, 1): "无差异属性",
        (3, 1): "反向属性",
        (4, 1): "反向属性",
        (5, 1): "反向属性"
    }
    
    def __init__(self, data: pd.DataFrame = None):
        self.data = data
        self.analysis_results = {}
        
    def load_data(self, data: pd.DataFrame) -> None:
        self.data = data
        self.analysis_results = {}
        
    def analyze(self, attribute_pairs: Dict[str, Tuple[str, str]]) -> None:
        if self.data is None:
            raise ValueError("请先加载数据")
            
        for attr_name, (func_col, dysfunc_col) in attribute_pairs.items():
            if func_col not in self.data.columns or dysfunc_col not in self.data.columns:
                raise ValueError(f"数据中不存在列: {func_col} 或 {dysfunc_col}")
                
            kano_counts = {cat: 0 for cat in set(self.KANO_CATEGORIES.values())}
            total = 0
            
            for _, row in self.data.iterrows():
                func_value = row[func_col]
                dysfunc_value = row[dysfunc_col]
                if (func_value, dysfunc_value) in self.KANO_CATEGORIES:
                    category = self.KANO_CATEGORIES[(func_value, dysfunc_value)]
                    kano_counts[category] += 1
                    total += 1
            
            kano_percentages = {cat: count / total * 100 for cat, count in kano_counts.items()}
            satisfaction = (kano_counts.get("魅力属性", 0) + kano_counts.get("期望属性", 0)) / total
            dissatisfaction = (kano_counts.get("必备属性", 0) + kano_counts.get("期望属性", 0)) / total
            
            self.analysis_results[attr_name] = {
                "percentages": kano_percentages,
                "satisfaction": satisfaction,
                "dissatisfaction": dissatisfaction,
                "dominant_category": max(kano_percentages, key=kano_percentages.get)
            }
    
    def get_results(self) -> Dict[str, Dict]:
        return self.analysis_results
    
    def plot_kano_percentages(self, attribute_name: str, ax: Optional[plt.Axes] = None) -> plt.Axes:
        if attribute_name not in self.analysis_results:
            raise ValueError(f"未找到属性 '{attribute_name}' 的分析结果")
            
        if ax is None:
            fig, ax = plt.subplots(figsize=(10, 6))
            
        results = self.analysis_results[attribute_name]
        percentages = results["percentages"]
        for cat in set(self.KANO_CATEGORIES.values()):
            if cat not in percentages:
                percentages[cat] = 0
                
        categories = ["必备属性", "期望属性", "魅力属性", "无差异属性", "反向属性"]
        values = [percentages.get(cat, 0) for cat in categories]
        
        bars = ax.bar(categories, values, color=['#FF6B6B', '#4ECDC4', '#1A535C', '#FFE66D', '#FF9F1C'])
        for bar in bars:
            height = bar.get_height()
            ax.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                    f'{height:.1f}%', ha='center', va='bottom')
        
        ax.set_title(f"{attribute_name}的Kano类别分布")
        ax.set_ylabel("百分比 (%)")
        ax.set_ylim(0, 100)
        
        return ax
    
    def plot_satisfaction_map(self, ax: Optional[plt.Axes] = None) -> plt.Axes:
        if not self.analysis_results:
            raise ValueError("没有分析结果可供绘制")
            
        if ax is None:
            fig, ax = plt.subplots(figsize=(12, 10))
            
        ax.axhline(y=0.5, color='gray', linestyle='--', alpha=0.5)
        ax.axvline(x=0.5, color='gray', linestyle='--', alpha=0.5)
        
        ax.text(0.75, 0.75, "魅力属性", ha='center', va='center', fontsize=14, bbox=dict(facecolor='white', alpha=0.5))
        ax.text(0.25, 0.75, "期望属性", ha='center', va='center', fontsize=14, bbox=dict(facecolor='white', alpha=0.5))
        ax.text(0.75, 0.25, "必备属性", ha='center', va='center', fontsize=14, bbox=dict(facecolor='white', alpha=0.5))
        ax.text(0.25, 0.25, "无差异/反向属性", ha='center', va='center', fontsize=14, bbox=dict(facecolor='white', alpha=0.5))
        
        colors = {
            "必备属性": "#FF6B6B",
            "期望属性": "#4ECDC4",
            "魅力属性": "#1A535C",
            "无差异属性": "#FFE66D",
            "反向属性": "#FF9F1C"
        }
        
        for attr_name, results in self.analysis_results.items():
            sat = results["satisfaction"]
            dis = results["dissatisfaction"]
            dominant_cat = results["dominant_category"]
            color = colors.get(dominant_cat, "#333333")
            ax.scatter(dis, sat, s=100, color=color, label=attr_name, alpha=0.7, edgecolors='w', linewidth=1)
            ax.annotate(attr_name, (dis, sat), xytext=(0, 10), textcoords="offset points", ha='center', fontsize=9)
        
        ax.set_title("惠山泥人Kano满意度分析图")
        ax.set_xlabel("不满意度系数 (如果不提供该属性)")
        ax.set_ylabel("满意度系数 (如果提供该属性)")
        ax.set_xlim(0, 1)
        ax.set_ylim(0, 1)
        
        # 使用导入的Patch创建图例
        legend_elements = [Patch(facecolor=color, label=cat) for cat, color in colors.items()]
        ax.legend(handles=legend_elements, title="主导类别", bbox_to_anchor=(1.05, 1), loc='upper left')
        
        return ax